// Copyright 2014 The Go Circuit Project
// Use of this source code is governed by the license for
// The Go Circuit Project, found in the LICENSE file.
//
// Authors:
//   2014 Chris Monson <chris@gocircuit.org>

package ripple

import (
	"fmt"
	"math/rand"
	"sync"
	"time"

	"circuit/kit/rh"
)

// procWaitFID
type procWaitFID struct {
	rh.AnchoredFID
	sync.Mutex

	waitChan chan error

	q   rh.Q
	gtm time.Time
}

// NewProcWait creates a new process wait file.
// On open, it attempts to wait for the process to complete.
func NewProcWait(waitChan chan error) rh.FID {
	fid := &procWaitFID{
		waitChan: waitChan,
		gtm:      time.Now(),
		q: rh.Q{
			ID:  uint64(rand.Int63()),
			Ver: 1,
		},
	}
	return fid
}

func (fid *procWaitFID) String() string {
	return fmt.Sprintf("procwait (%p) %v", fid, fid.Q())
}

func (fid *procWaitFID) Q() rh.Q {
	return fid.q
}

func (fid *procWaitFID) Open(flag rh.Flag, intr rh.Intr) (err error) {
	defer un(lock(fid))

	// avoid blocking simulated opens from the fuse/rh setattr hack
	if flag.Create || flag.Truncate || flag.Deny {
		return rh.ErrPerm
	}

	select {
	case err := <-fid.waitChan:
		return err
	case <-intr:
		return rh.ErrIntr
	}

	return nil
}

func (fid *procWaitFID) Read(_ int64, count int, intr rh.Intr) (chunk rh.Chunk, err error) {
	return rh.ByteChunk([]byte{}), nil
}

func (fid *procWaitFID) Write(offset int64, data rh.Chunk, intr rh.Intr) (n int, err error) {
	return 0, rh.ErrPerm
}

func (fid *procWaitFID) Clunk() {
}

func (fid *procWaitFID) Walk(wname []string) (rh.FID, error) {
	if len(wname) > 0 {
		return nil, rh.ErrClash
	}
	// Duplicate these guys so that we can have multiple openers.
	return NewProcWait(fid.waitChan), nil
}

func (fid *procWaitFID) Stat() (*rh.Dir, error) {
	return &rh.Dir{
		Q:      fid.q,
		Mode:   rh.Mode{Attr: rh.ModeIO},
		Perm:   0444, // r--r--r--, acts as /dev/null for writing and empty file for reading
		Atime:  fid.gtm,
		Mtime:  fid.gtm,
		Name:   "procwait",
		Length: 0,
		Uid:    uid(),
		Gid:    gid(),
	}, nil
}
